package com.heima.admin.service.impl;

import com.alibaba.fastjson.JSON;
import com.heima.admin.mapper.AdChannelMapper;
import com.heima.admin.mapper.AdSensitiveMapper;
import com.heima.admin.service.WemediaNewsAutoScanService;
import com.heima.aliyun.GreeTextScan;
import com.heima.aliyun.GreenImageScan;
import com.heima.common.exception.CustException;
import com.heima.feigns.article.ArticleFeign;
import com.heima.feigns.wemedia.WemediaFeign;
import com.heima.model.admin.pojos.AdChannel;
import com.heima.model.article.dtos.ArticleDto;
import com.heima.model.common.constants.WemediaConstants;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.wemedia.pojos.WmNews;
import com.heima.model.wemedia.pojos.WmUser;
import com.heima.utils.common.SensitiveWordUtil;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Slf4j
@Service
@Transactional
public class WemediaNewsAutoScanServiceImpl implements WemediaNewsAutoScanService {
    @Autowired
    AdSensitiveMapper sensitiveMapper;

    @Autowired
    WemediaFeign wemediaFeign;

    @Autowired
    GreeTextScan greeTextScan;

    @Autowired
    GreenImageScan greenImageScan;

    @Autowired
    AdChannelMapper adChannelMapper;

    @Autowired
    ArticleFeign articleFeign;

    @Value("${file.oss.web-site}")
    private String webSite;

    /**
     * 自媒体文章审核
     *
     * @param wmNewsId
     */
    @Override
    @GlobalTransactional
    public void autoScanByMediaNewsId(Integer wmNewsId) {
        //参数检查
        if (wmNewsId==null){
            log.info("wmNewsId 为空");
            CustException.cust(AppHttpCodeEnum.PARAM_INVALID);
            return;
        }
        //1.根据文章的id查询自媒体文章
        WmNews wmNews = wemediaFeign.findById(wmNewsId);
        if (wmNews == null){
            log.error("文章id不能为空");
            CustException.cust(AppHttpCodeEnum.DATA_NOT_EXIST);
            return;
        }
        //2.文章状态=4(人工审核通过)  且发布时间小于等于当前时间，直接保存到文章库
        if (wmNews.getStatus().equals(WmNews.Status.ADMIN_SUCCESS.getCode()) && wmNews.getPublishTime().getTime() <= System.currentTimeMillis()){
            saveAppArticle(wmNews);
            return;
        }

        //3.文章状态=8(文章审核通过，未发布)  且发布时间小于等于当前时间，直接保存到文章库
        if (wmNews.getStatus().equals(WmNews.Status.SUCCESS.getCode()) && wmNews.getPublishTime().getTime() <= System.currentTimeMillis()){
            saveAppArticle(wmNews);
            return;
        }
        //4.文章状态=1  未审核
        if (wmNews.getStatus().equals(WmNews.Status.SUBMIT.getCode())){
            //解析文章内容获取文本和照片内容
            Map<String,Object> map =  handleTextAndImages(wmNews);
           //4.1. 自管理敏感词
            boolean isSensitiveScan = handleSensitive((String) map.get("text"), wmNews);
            if (isSensitiveScan) return;

            //4.2. 阿里云-文本内容审核
            boolean isTextScan = handleTextScan((String) map.get("text"), wmNews);
            if (!isTextScan) return;

            //4.3. 阿里云-图片审核
            boolean isImageScan = handkeImageScan((List<String>) map.get("images"), wmNews);
            if (!isImageScan) return;

            //4.4. 如果发布时间 大于 当前时间，修改wmNews 文章状态=8
            if (wmNews.getPublishTime().getTime() > System.currentTimeMillis()){
                updateWmNews(wmNews, WemediaConstants.WM_NEWS_AUTHED_STATUS,"文章审核通过，待发布");
                return;
            }
        }

        //5. 审核通过，保存文章相关信息（三张表），修改文章状态=9 已发布
        saveAppArticle(wmNews);
        //TODO  6. ES同步索引库
    }

    /*
    * 阿里云审核图片
    * */
    private boolean handkeImageScan(List<String> images, WmNews wmNews) {

        //1.判断 无图则无需审核
        if (images == null && images.size()== 0){
            return true;
        }
        boolean flag = true;
        try {
            //图片去重
            images = images.stream().distinct()
                    .collect(Collectors.toList());
            Map map = greenImageScan.imageUrlScan(images);
            //2.审核不通过
            if (map.get("suggestion").equals("block")){
                flag = false;
                updateWmNews(wmNews, (short) 2,"文章图片有违规,审核不通过");
            }
            //3.转入人工审核
            if (map.get("suggestion").equals("review")){
                flag = false;
                updateWmNews(wmNews, (short) 3,"文章图片存在不确定元素，转入人工审核");
            }
        } catch (Exception e) {
            e.printStackTrace();
            flag = false;
            updateWmNews(wmNews, (short) 3,"阿里云图片审核失败，转入人工审核");
        }
        return flag;
    }


    /*
    * 阿里云审核文本内容
    * */
    private boolean handleTextScan(String text, WmNews wmNews) {
        boolean flag = true;

        try {
            Map map = greeTextScan.greeTextScan(text);

            //1.审核不通过
            if (map.get("suggestion").equals("block")){
                flag = false;
                updateWmNews(wmNews, (short) 2,"文本内容含有敏感词汇");
            }
            //2.文章需要转入人工审核
            if (map.get("suggestion").equals("review")){
                flag = false;
                updateWmNews(wmNews, (short) 3,"文本内容需要转入人工审核");
            }

        } catch (Exception e) {
            e.printStackTrace();
            log.error("文章内容阿里云审核失败，转入人工审核，e:{}" + e);
            flag = false;
            updateWmNews(wmNews, (short) 3,"文章内容阿里云审核失败，需要转入人工审核");
        }
        return flag;
    }


    /*
    * 自管理敏感词审核
    * */


    private boolean handleSensitive(String text, WmNews wmNews) {
        //查询所有敏感词
        boolean flag = false;
        List<String> sensitiveList = sensitiveMapper.findAllSensitive();
        //初始化
        SensitiveWordUtil.initMap(sensitiveList);
        //匹配
        Map<String, Integer> map = SensitiveWordUtil.matchWords(text);
        //判断
        if (map.size() > 0){
            flag = true;
            updateWmNews(wmNews,(short) 2,"文章包含了敏感词" + map);
        }
        return flag;
    }


    /*
    * 修改更新文章
    * */
    private void updateWmNews(WmNews wmNews, short code, String msg) {
        wmNews.setStatus(code);
        wmNews.setReason(msg);
        ResponseResult result = wemediaFeign.updateWmNews(wmNews);
        if (!result.getCode().equals(0)){
            CustException.cust(AppHttpCodeEnum.WEMEDIA_UPDATE_ERROR);
        }
    }



    /*
    *抽取文章的 文本和图片（包含封面的图片[不带前缀]）
    * */
    private Map<String, Object> handleTextAndImages(WmNews wmNews) {
        //1.获取文章内容并转换对象
        String content = wmNews.getContent();
        if (StringUtils.isBlank(content) || content.length() > 10000){
            return null;
        }
        List<Map> contentList = JSON.parseArray(content, Map.class);

        //2.解析文章内容中的文本
        String contents = contentList.stream()
                .filter(x -> x.get("type").equals("text"))
                .map(y -> y.get("value").toString())
                .collect(Collectors.joining("_hmtt_"));

        //文章标题 参与审核
        contents = wmNews.getTitle() + "_hmtt_" + contents;

        //3解析文章图片
        List<String> images = contentList.stream()
                .filter(x -> x.get("type").equals("image"))
                .map(y -> y.get("value").toString())
                .collect(Collectors.toList());

        //处理文章封面图片
        String imageCover = wmNews.getImages();
        if (StringUtils.isNotBlank(imageCover)){
            images.addAll(
                    Stream.of(imageCover.split(","))
                    .map(x -> webSite+x)
                    .collect(Collectors.toList())
            );
        }
        //封装结果
        Map<String, Object> resultMap = new HashMap<>();
        resultMap.put("text",contents);
        resultMap.put("images",images);
        return resultMap;
    }

    /*
    * 保存文章库
    * */
    private void saveAppArticle(WmNews wmNews) {
        // 保存成功 文章ID
        ResponseResult result = saveArticle(wmNews);

        if (result.getCode() != 0) {
            throw new RuntimeException("文章审核保存app文章失败");
        }

        // data 设置文章ID
        wmNews.setArticleId((Long) result.getData());
        // 更新自媒体文章状态
        updateWmNews(wmNews, WmNews.Status.PUBLISHED.getCode(), "已发布");
    }



    /*
    *执行保存三张表
    * */
    private ResponseResult saveArticle(WmNews wmNews) {
        //1 封装数据 dto
        ArticleDto articleDto = new ArticleDto();

        BeanUtils.copyProperties(wmNews, articleDto);
        articleDto.setId(null);
        if (wmNews.getArticleId()!=null) {
            articleDto.setId( wmNews.getArticleId() );
        }
        // 布局
        articleDto.setLayout(wmNews.getType());
        articleDto.setFlag((byte) 0);

        //2 设置频道
        if (wmNews.getChannelId() != null) {
            articleDto.setChannelId(wmNews.getChannelId());
            AdChannel channel = adChannelMapper.selectById(wmNews.getChannelId());
            if (channel != null) {
                articleDto.setChannelName(channel.getName());
            }
        }

        //3 设置作者信息
        // 查wm_user 状态
        WmUser wmUser = wemediaFeign.findWmUserById(wmNews.getUserId());
        if (wmUser == null || wmUser.getStatus().intValue() != 9) { // 非法用户
            CustException.cust(AppHttpCodeEnum.ADMIN_ADUSER_ISNTOEXIT_ERROR);
        }
        if (StringUtils.isNotBlank(wmUser.getName())) {
            // 自媒体名称不能修改
            articleDto.setAuthorName(wmUser.getName());
            // 作者id 尽量减少远程调用
        }

        //4 文章内容
        articleDto.setContent(wmNews.getContent());

        // 发起远程调用 保存 三张表数据, 返回值必须携带文章id
        return articleFeign.saveArticle(articleDto);
    }
}
